package io.inputstream ;

import java.io.ByteArrayInputStream ;
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
import java.io.IOException ;
import java.security.DigestInputStream ;
import java.security.DigestOutputStream ;
import java.security.MessageDigest ;
import java.security.NoSuchAlgorithmException ;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream ;

/**
 * 摘要输入输出流
 * 摘要流主要用于验证输入流以及输出流在传输过程中的安全性
 * DigestInputStream在构造的时候必须传入一个MessageDigest摘要类，用来处理摘要流的摘要算法功能
 * DigestInputStream的on(boolean)方法控制摘要的功能，on(false)的时候，摘要流退化为普通的输入输出流
 * 在DigestInputStream将数据读入到流中时，read()方法会调用DigestInputStream内联的MessageDigest的update方法，所以在读完数据后，调用getMessageDigest().digest()生成数据的摘要
 * 输出流DigestOutputStream也是一样，调用write()方法写数据时，也会调用内联的MessageDigest的update方法。数据写完后，调用getMessageDigest().digest()也会生产一个数据摘要。
 * 因此，只需要对比两个摘要，就可以判断输入流和输出流处理的数据是否一致。
 * @author 80002165
 * @date 2017年1月15日 上午9:10:58
 */
public class TestDigestInputStream {
    public static void main(String[] args) {
//        testMessageDigest() ;
//         testDigestOutStream() ;
//        testDigestInputStream() ;
//        defaultMessageDigest() ;
        
        try {
            testDigestStraem() ;
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }
    }
    
    private static void testDigestOutStream() {
        String info = "test_MessageDigest" ; // D4:1D:8C:D9:8F:00:B2:04:E9:80:09:98:EC:F8:42:7E
        ByteOutputStream bos = new ByteOutputStream() ;
        DigestOutputStream dos = null ;
//        bos.write(info.getBytes());
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5") ;
            dos = new DigestOutputStream(bos, digest) ;
            dos.on(false); //false : D4:1D:8C:D9:8F:00:B2:04:E9:80:09:98:EC:F8:42:7E
            dos.write(info.getBytes()); //6A:6D:4F:DA:A2:70:82:D6:FC:50:F6:AC:52:48:F5:AE
            byte[] digestData = dos.getMessageDigest().digest() ;
            System.out.println(byte2hex(digestData)) ;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace() ;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close() ;
                } catch (IOException e) {
                    e.printStackTrace() ;
                }
            }
            
            if (bos != null) {
                bos.close() ;
            }
        }
    }
    
    /**
     * 只有调用DigestInputStream的read方法，才能计算出数据的摘要
     * @author 80002165
     * @date 2017年1月15日 下午4:03:55
     */
    private static void testDigestInputStream() {
        String info = "test_MessageDigest" ; // D4:1D:8C:D9:8F:00:B2:04:E9:80:09:98:EC:F8:42:7E
        byte[] cache = new byte[0] ;
        ByteArrayInputStream bais = new ByteArrayInputStream(cache) ;
        System.out.println("bytearrayinputstream data length is " + bais.available()) ;
        DigestInputStream dis = null ;
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5") ;
            dis = new DigestInputStream(bais, digest) ;
            System.out.println("digestinputstream data length is " + dis.available()) ;
            dis.read(info.getBytes(), 0, info.getBytes().length) ;
            System.out.println("digestinputstream data length is " + dis.available()) ;
            int len = 0;
            byte[] datacache = new byte[12] ;
            StringBuilder sb = new StringBuilder() ;
            while((len = dis.read(datacache)) != -1){
                sb.append(new String(datacache, 0, len)) ;
            }
            System.out.println(sb.toString()) ;
            byte[] disData = dis.getMessageDigest().digest() ;
            System.out.println(byte2hex(disData)) ;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace() ;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dis != null) {
                try {
                    dis.close() ;
                } catch (IOException e) {
                    e.printStackTrace() ;
                }
            }
            
            if (bais != null) {
                try {
                    bais.close() ;
                } catch (IOException e) {
                    e.printStackTrace() ;
                }
            }
        }
    }
    
    /**
     * 
     * @author 80002165
     * @date 2017年1月15日 下午4:02:59
     */
    private static void testMessageDigest() {
        String info = "test_MessageDigest" ; // 6A:6D:4F:DA:A2:70:82:D6:FC:50:F6:AC:52:48:F5:AE
        // info = "more_test_MessageDigest" ;
        // //8B:22:67:B7:62:A5:92:E0:B4:44:D6:AB:14:E9:0F:91
        try {
            MessageDigest md = MessageDigest.getInstance("MD5") ;
            md.update(info.getBytes()) ;
            byte[] digest = md.digest() ;
            System.out.println(byte2hex(digest)) ;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace() ;
        }
    }
    
    /**
     * 二进制转换为字符
     * 
     * @author 80002165
     * @date 2017年1月15日 上午10:18:00
     * @param data
     * @return
     */
    private static String byte2hex(byte[] data) {
        StringBuilder sb = new StringBuilder() ;
        String stmp = "" ;
        for (int i = 0; i < data.length; i++) {
            stmp = Integer.toHexString(data[i] & 0xff) ;
            if (stmp.length() == 1)
                sb.append("0").append(stmp) ;
            else
                sb.append(stmp) ;
            if (i < data.length - 1)
                sb.append(":") ;
        }
        return sb.toString().toUpperCase() ;
    }
    
    /**
     * 没有任何数据，MessageDigest的digest会默认生成一个摘要
     * @author 80002165
     * @date 2017年1月15日 下午4:03:10
     */
    private static void defaultMessageDigest(){
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5") ;
            byte[] digestData = digest.digest() ;
            //D4:1D:8C:D9:8F:00:B2:04:E9:80:09:98:EC:F8:42:7E
            System.out.println(byte2hex(digestData)) ;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        
    }
    
    private static void testDigestStraem() throws NoSuchAlgorithmException, IOException{
        String info = "test_MessageDigest" ;
        MessageDigest digest = MessageDigest.getInstance("MD5") ;
        DigestOutputStream dos = new DigestOutputStream(new FileOutputStream("E:/testDigestStream.txt"), digest) ;
        dos.write(info.getBytes());
        byte[] dd1 = dos.getMessageDigest().digest() ;
        System.out.println(byte2hex(dd1)) ; //6A:6D:4F:DA:A2:70:82:D6:FC:50:F6:AC:52:48:F5:AE
        
        dos.close();
        
        MessageDigest digest1 = MessageDigest.getInstance("MD5") ;
        DigestInputStream dis = new DigestInputStream(new FileInputStream("E:/testDigestStream.txt"), digest1) ;
        System.out.println("dis length:"+dis.available()) ; //dis length:18
        int len = 0 ;
        byte[] cache = new byte[20] ;
        StringBuilder sb = new StringBuilder() ;
        while((len = dis.read(cache)) != -1) {
            sb.append(new String(cache, 0, len)) ;
        }
        System.out.println(sb.toString()) ; //test_MessageDigest
        byte[] dd2 = dis.getMessageDigest().digest() ;
        System.out.println(byte2hex(dd2)) ; //6A:6D:4F:DA:A2:70:82:D6:FC:50:F6:AC:52:48:F5:AE
        
        dis.close();
     }
}
